home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / Mail / fio.c < prev    next >
C/C++ Source or Header  |  1990-05-02  |  10KB  |  482 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#)fio.c    5.20 (Berkeley) 1/16/89";
  20. #endif /* not lint */
  21.  
  22. #include "rcv.h"
  23. #include <sys/stat.h>
  24. #include <sys/file.h>
  25. #include <sys/wait.h>
  26. #include <errno.h>
  27.  
  28. char *newfgets();
  29.  
  30. /*
  31.  * Mail -- a mail program
  32.  *
  33.  * File I/O.
  34.  */
  35.  
  36. /*
  37.  * Set up the input pointers while copying the mail file into
  38.  * /tmp.
  39.  */
  40. setptr(ibuf)
  41.     register FILE *ibuf;
  42. {
  43.     register c;
  44.     register char *cp, *cp2;
  45.     register count;
  46.     char linebuf[LINESIZE];
  47.     int maybe, inhead;
  48.     FILE *mestmp;
  49.     off_t offset;
  50.     struct message this;
  51.     extern char tempSet[];
  52.  
  53.     if ((c = opentemp(tempSet)) < 0)
  54.         exit(1);
  55.     if ((mestmp = fdopen(c, "r+")) == NULL)
  56.         panic("Can't open temporary");
  57.     msgCount = 0;
  58.     maybe = 1;
  59.     inhead = 0;
  60.     offset = 0;
  61.     this.m_flag = MUSED|MNEW;
  62.     this.m_size = 0;
  63.     this.m_lines = 0;
  64.     this.m_block = 0;
  65.     this.m_offset = 0;
  66.     for (;;) {
  67.         if (newfgets(linebuf, LINESIZE, ibuf) == NULL) {
  68.             if (append(&this, mestmp)) {
  69.                 perror(tempSet);
  70.                 exit(1);
  71.             }
  72. #ifdef notdef
  73.             /*
  74.              * Don't close ibuf here, because our caller
  75.              * closes it unconditionally.
  76.              */
  77.             fclose(ibuf);
  78. #endif
  79.             makemessage(mestmp);
  80.             return;
  81.         }
  82.         count = strlen(linebuf);
  83.         (void) fwrite(linebuf, sizeof *linebuf, count, otf);
  84.         if (ferror(otf)) {
  85.             perror("/tmp");
  86.             exit(1);
  87.         }
  88.         linebuf[count - 1] = 0;
  89.         if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
  90.             msgCount++;
  91.             if (append(&this, mestmp)) {
  92.                 perror(tempSet);
  93.                 exit(1);
  94.             }
  95.             this.m_flag = MUSED|MNEW;
  96.             this.m_size = 0;
  97.             this.m_lines = 0;
  98.             this.m_block = blockof(offset);
  99.             this.m_offset = offsetof(offset);
  100.             inhead = 1;
  101.         } else if (linebuf[0] == 0) {
  102.             inhead = 0;
  103.         } else if (inhead) {
  104.             for (cp = linebuf, cp2 = "status";; cp++) {
  105.                 if ((c = *cp2++) == 0) {
  106.                     while (isspace(*cp++))
  107.                         ;
  108.                     if (cp[-1] != ':')
  109.                         break;
  110.                     while (c = *cp++)
  111.                         if (c == 'R')
  112.                             this.m_flag |= MREAD;
  113.                         else if (c == 'O')
  114.                             this.m_flag &= ~MNEW;
  115.                     inhead = 0;
  116.                     break;
  117.                 }
  118.                 if (*cp != c && *cp != toupper(c))
  119.                     break;
  120.             }
  121.         }
  122.         offset += count;
  123.         this.m_size += count;
  124.         this.m_lines++;
  125.         maybe = linebuf[0] == 0;
  126.     }
  127. }
  128.  
  129. /*
  130.  * Drop the passed line onto the passed output buffer.
  131.  * If a write error occurs, return -1, else the count of
  132.  * characters written, including the newline.
  133.  */
  134. putline(obuf, linebuf)
  135.     FILE *obuf;
  136.     char *linebuf;
  137. {
  138.     register int c;
  139.  
  140.     c = strlen(linebuf);
  141.     (void) fwrite(linebuf, sizeof *linebuf, c, obuf);
  142.     (void) putc('\n', obuf);
  143.     if (ferror(obuf))
  144.         return (-1);
  145.     return (c + 1);
  146. }
  147.  
  148. /*
  149.  * Read up a line from the specified input into the line
  150.  * buffer.  Return the number of characters read.  Do not
  151.  * include the newline at the end.
  152.  */
  153. readline(ibuf, linebuf, linesize)
  154.     FILE *ibuf;
  155.     char *linebuf;
  156. {
  157.     register int n;
  158.  
  159.     clearerr(ibuf);
  160.     if (fgets(linebuf, linesize, ibuf) == NULL)
  161.         return -1;
  162.     n = strlen(linebuf);
  163.     if (n > 0 && linebuf[n - 1] == '\n')
  164.         linebuf[--n] = '\0';
  165.     return n;
  166. }
  167.  
  168. /*
  169.  * Return a file buffer all ready to read up the
  170.  * passed message pointer.
  171.  */
  172. FILE *
  173. setinput(mp)
  174.     register struct message *mp;
  175. {
  176.  
  177.     fflush(otf);
  178.     if (fseek(itf, positionof(mp->m_block, mp->m_offset), 0) < 0) {
  179.         perror("fseek");
  180.         panic("temporary file seek");
  181.     }
  182.     return (itf);
  183. }
  184.  
  185. /*
  186.  * Take the data out of the passed ghost file and toss it into
  187.  * a dynamically allocated message structure.
  188.  */
  189. makemessage(f)
  190.     FILE *f;
  191. {
  192.     register size = (msgCount + 1) * sizeof (struct message);
  193.     off_t lseek();
  194.  
  195.     if (message != 0)
  196.         free((char *) message);
  197.     if ((message = (struct message *) malloc((unsigned) size)) == 0)
  198.         panic("Insufficient memory for %d messages", msgCount);
  199.     dot = message;
  200.     size -= sizeof (struct message);
  201.     fflush(f);
  202.     (void) lseek(fileno(f), (long) sizeof *message, 0);
  203.     if (read(fileno(f), (char *) message, size) != size)
  204.         panic("Message temporary file corrupted");
  205.     message[msgCount].m_size = 0;
  206.     message[msgCount].m_lines = 0;
  207.     fclose(f);
  208. }
  209.  
  210. /*
  211.  * Append the passed message descriptor onto the temp file.
  212.  * If the write fails, return 1, else 0
  213.  */
  214. append(mp, f)
  215.     struct message *mp;
  216.     FILE *f;
  217. {
  218.     return fwrite((char *) mp, sizeof *mp, 1, f) != 1;
  219. }
  220.  
  221. /*
  222.  * Delete a file, but only if the file is a plain file.
  223.  */
  224. remove(name)
  225.     char name[];
  226. {
  227.     struct stat statb;
  228.     extern int errno;
  229.  
  230.     if (stat(name, &statb) < 0)
  231.         return(-1);
  232.     if ((statb.st_mode & S_IFMT) != S_IFREG) {
  233.         errno = EISDIR;
  234.         return(-1);
  235.     }
  236.     return unlink(name);
  237. }
  238.  
  239. static int sigdepth;        /* depth of holdsigs() */
  240. static int omask;
  241. /*
  242.  * Hold signals SIGHUP, SIGINT, and SIGQUIT.
  243.  */
  244. holdsigs()
  245. {
  246.  
  247.     if (sigdepth++ == 0)
  248.         omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT));
  249. }
  250.  
  251. /*
  252.  * Release signals SIGHUP, SIGINT, and SIGQUIT.
  253.  */
  254. relsesigs()
  255. {
  256.  
  257.     if (--sigdepth == 0)
  258.         sigsetmask(omask);
  259. }
  260.  
  261. /*
  262.  * Open a temp file by creating and unlinking.
  263.  * Return the open file descriptor.
  264.  */
  265. opentemp(file)
  266.     char file[];
  267. {
  268.     int f;
  269.  
  270.     if ((f = open(file, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0)
  271.         perror(file);
  272.     remove(file);
  273.     return (f);
  274. }
  275.  
  276. /*
  277.  * Determine the size of the file possessed by
  278.  * the passed buffer.
  279.  */
  280. off_t
  281. fsize(iob)
  282.     FILE *iob;
  283. {
  284.     struct stat sbuf;
  285.  
  286.     if (fstat(fileno(iob), &sbuf) < 0)
  287.         return 0;
  288.     return sbuf.st_size;
  289. }
  290.  
  291. /*
  292.  * Evaluate the string given as a new mailbox name.
  293.  * Supported meta characters:
  294.  *    %    for my system mail box
  295.  *    %user    for user's system mail box
  296.  *    #    for previous file
  297.  *    &    invoker's mbox file
  298.  *    +file    file in folder directory
  299.  *    any shell meta character
  300.  * Return the file name as a dynamic string.
  301.  */
  302. char *
  303. expand(name)
  304.     register char *name;
  305. {
  306.     char xname[PATHSIZE];
  307.     char cmdbuf[PATHSIZE];        /* also used for file names */
  308.     register int pid, l;
  309.     register char *cp, *shell;
  310.     int pivec[2];
  311.     struct stat sbuf;
  312.     extern union wait wait_status;
  313.  
  314.     /*
  315.      * The order of evaluation is "%" and "#" expand into constants.
  316.      * "&" can expand into "+".  "+" can expand into shell meta characters.
  317.      * Shell meta characters expand into constants.
  318.      * This way, we make no recursive expansion.
  319.      */
  320.     switch (*name) {
  321.     case '%':
  322.         findmail(name[1] ? name + 1 : myname, xname);
  323.         return savestr(xname);
  324.     case '#':
  325.         if (name[1] != 0)
  326.             break;
  327.         if (prevfile[0] == 0) {
  328.             printf("No previous file\n");
  329.             return NOSTR;
  330.         }
  331.         return savestr(prevfile);
  332.     case '&':
  333.         if (name[1] == 0 && (name = value("MBOX")) == NOSTR)
  334.             name = "~/mbox";
  335.         /* fall through */
  336.     }
  337.     if (name[0] == '+' && getfold(cmdbuf) >= 0) {
  338.         sprintf(xname, "%s/%s", cmdbuf, name + 1);
  339.         name = savestr(xname);
  340.     }
  341.     /* catch the most common shell meta character */
  342.     if (name[0] == '~' && (name[1] == '/' || name[1] == '\0')) {
  343.         sprintf(xname, "%s%s", homedir, name + 1);
  344.         name = savestr(xname);
  345.     }
  346.     if (!anyof(name, "~{[*?$`'\"\\"))
  347.         return name;
  348.     if (pipe(pivec) < 0) {
  349.         perror("pipe");
  350.         return name;
  351.     }
  352.     sprintf(cmdbuf, "echo %s", name);
  353.     if ((shell = value("SHELL")) == NOSTR)
  354.         shell = SHELL;
  355.     pid = start_command(shell, 0, -1, pivec[1], "-c", cmdbuf, NOSTR);
  356.     if (pid < 0) {
  357.         close(pivec[0]);
  358.         close(pivec[1]);
  359.         return NOSTR;
  360.     }
  361.     close(pivec[1]);
  362.     l = read(pivec[0], xname, BUFSIZ);
  363.     close(pivec[0]);
  364.     if (wait_child(pid) < 0 && wait_status.w_termsig != SIGPIPE) {
  365.         fprintf(stderr, "\"%s\": Expansion failed.\n", name);
  366.         return NOSTR;
  367.     }
  368.     if (l < 0) {
  369.         perror("read");
  370.         return NOSTR;
  371.     }
  372.     if (l == 0) {
  373.         fprintf(stderr, "\"%s\": No match.\n", name);
  374.         return NOSTR;
  375.     }
  376.     if (l == BUFSIZ) {
  377.         fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name);
  378.         return NOSTR;
  379.     }
  380.     xname[l] = 0;
  381.     for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
  382.         ;
  383.     cp[1] = '\0';
  384.     if (index(xname, ' ') && stat(xname, &sbuf) < 0) {
  385.         fprintf(stderr, "\"%s\": Ambiguous.\n", name);
  386.         return NOSTR;
  387.     }
  388.     return savestr(xname);
  389. }
  390.  
  391. /*
  392.  * Determine the current folder directory name.
  393.  */
  394. getfold(name)
  395.     char *name;
  396. {
  397.     char *folder;
  398.  
  399.     if ((folder = value("folder")) == NOSTR)
  400.         return (-1);
  401.     if (*folder == '/')
  402.         strcpy(name, folder);
  403.     else
  404.         sprintf(name, "%s/%s", homedir, folder);
  405.     return (0);
  406. }
  407.  
  408. /*
  409.  * Return the name of the dead.letter file.
  410.  */
  411. char *
  412. getdeadletter()
  413. {
  414.     register char *cp;
  415.  
  416.     if ((cp = value("DEAD")) == NOSTR || (cp = expand(cp)) == NOSTR)
  417.         cp = expand("~/dead.letter");
  418.     else if (*cp != '/') {
  419.         char buf[PATHSIZE];
  420.  
  421.         (void) sprintf(buf, "~/%s", cp);
  422.         cp = expand(buf);
  423.     }
  424.     return cp;
  425. }
  426.  
  427. /*
  428.  * A nicer version of Fdopen, which allows us to fclose
  429.  * without losing the open file.
  430.  */
  431. FILE *
  432. Fdopen(fildes, mode)
  433.     char *mode;
  434. {
  435.     int f;
  436.  
  437.     if ((f = dup(fildes)) < 0) {
  438.         perror("dup");
  439.         return (NULL);
  440.     }
  441.     return fdopen(f, mode);
  442. }
  443.  
  444. int warn=0;
  445. /*
  446.  * A version of fgets, which will warn if it reads nulls.
  447.  */
  448. char *
  449. newfgets(bufferPtr, maxChars, stream)
  450.     char *bufferPtr;            /* Where to place characters.  Must have
  451.                                  * at least maxChars bytes of storage. */
  452.     register int maxChars;      /* Maximum number of characters to read
  453.                                  * from stream. */
  454.     register FILE *stream;      /* Stream from which to read characters. */
  455. {
  456.     register char *destPtr = bufferPtr;
  457.     register int c;
  458.  
  459.     for (maxChars--; maxChars > 0; maxChars--) {
  460.         c = getc(stream);
  461.         if (c < 0) {
  462.             *destPtr = 0;
  463.             return NULL;
  464.         }
  465.     if (c==0) {
  466.         if (!warn) {
  467.         fprintf(stderr,"Warning: encountered nulls at %d.  %s\n",
  468.             ftell(stream), "Mail spool file may be damaged.");
  469.         warn++;
  470.         }
  471.     } else {
  472.         *destPtr = c;
  473.         destPtr++;
  474.     }
  475.         if (c == '\n') {
  476.             break;
  477.         }
  478.     }
  479.     *destPtr = 0;
  480.     return bufferPtr;
  481. }
  482.